package org.example.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.example.core.exception.BusinessException;
import org.example.core.utils.DataValidator;
import org.example.sys.entity.TSysMenu;
import org.example.sys.entity.TSysRole;
import org.example.sys.entity.TSysUser;
import org.example.sys.entity.TSysUserRole;
import org.example.sys.entity.dto.UserDTO;
import org.example.sys.entity.param.UserParam;
import org.example.sys.mapper.TSysRoleMenuMapper;
import org.example.sys.mapper.TSysUserMapper;
import org.example.sys.mapper.TSysUserRoleMapper;
import org.example.sys.service.TSysUserService;
import org.example.core.utils.BeanConvertUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 用户表(TSysUser)表服务实现类
 */
@Slf4j
@Service("tSysUserService")
public class TSysUserServiceImpl extends ServiceImpl<TSysUserMapper, TSysUser> implements TSysUserService {

    @Resource
    private TSysUserMapper userMapper;
    @Resource
    private TSysUserRoleMapper userRoleMapper;
    @Resource
    private TSysRoleMenuMapper roleMenuMapper;
    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    /**
     * 用户名称获取用户信息
     * @param username
     * @return
     */
    @Override
    public UserDTO getByUsername(String username) {
        if (StringUtils.isBlank(username)) {
            return null;
        }
        TSysUser user = baseMapper.selectOne(new LambdaQueryWrapper<TSysUser>()
                .eq(TSysUser::getUsername, username));
        return convertToUserDTO(user);
    }


    /**
     * 用户id获取用户信息
     * @param loginUserId
     * @return
     */
    @Override
    public UserDTO getByIdRel(Long loginUserId) {
        UserParam param = new UserParam();
        param.setUserId(loginUserId);
        TSysUser user = baseMapper.selectListRel(param);
        return convertToUserDTO(user);
    }

    /**
     * 验证密码
     * @param password
     * @param paramPassword
     * @return
     */
    @Override
    public boolean comparePassword(String password, String paramPassword) {
        log.info(">>>password:{},paramPassword:{},{}", password,paramPassword,encodePassword(paramPassword));
        return bCryptPasswordEncoder.matches(paramPassword, password);
    }


    /**
     * 获取加密密码
     * @param password
     * @return
     */
    @Override
    public String encodePassword(String password) {
        return StringUtils.isBlank(password) ? null : bCryptPasswordEncoder.encode(password);
    }

    /**
     * 保存用户
     * @param user
     * @return
     */
    @Transactional(rollbackFor = {Exception.class}, isolation = Isolation.SERIALIZABLE)
    @Override
    public boolean saveUser(UserDTO user) {
        validateUserUniqueness(user);
        boolean result = baseMapper.insert(user) > 0;
        if (result) {
            saveUserRoles(user);
        }
        return result;
    }

    /**
     * 更新用户
     * @param user
     * @return
     */
    @Transactional(rollbackFor = {Exception.class})
    @Override
    public boolean updateUser(UserDTO user) {
        validateUserUniqueness(user);
        boolean result = baseMapper.updateById(user) > 0;
        if (result) {
            userRoleMapper.delete(new LambdaUpdateWrapper<TSysUserRole>().eq(TSysUserRole::getUserId, user.getUserId()));
            saveUserRoles(user);
        }
        return result;
    }

    /**
     * 校验用户信息
     * @param user
     */
    private void validateUserUniqueness(UserDTO user) {
        if (StringUtils.isNotEmpty(user.getUsername())){
            Long result = baseMapper.selectCount(new LambdaQueryWrapper<TSysUser>()
                    .eq(TSysUser::getUsername, user.getUsername())
                    .ne(TSysUser::getUserId, user.getUserId()));
            if(result > 0) {
                throw new BusinessException("账号已存在");
            }
        }
        if (StringUtils.isNotEmpty(user.getPhone())){
            Long result = baseMapper.selectCount(new LambdaQueryWrapper<TSysUser>()
                    .eq(TSysUser::getPhone, user.getPhone())
                    .ne(TSysUser::getUserId, user.getUserId()));
            if(result > 0) {
                throw new BusinessException("手机号已存在");
            }
            if(!DataValidator.isValidPhone(user.getPhone())){
                throw new BusinessException("手机号不正确");
            }
        }
        if (StringUtils.isNotEmpty(user.getEmail())){
            Long result = baseMapper.selectCount(new LambdaQueryWrapper<TSysUser>()
                    .eq(TSysUser::getEmail, user.getEmail())
                    .ne(TSysUser::getUserId, user.getUserId()));
            if(result > 0) {
                throw new BusinessException("邮箱已存在");
            }
            if(!DataValidator.isValidEmail(user.getEmail())){
                throw new BusinessException("邮箱格式不正确");
            }
        }
    }

    /**
     * 用户添加角色
     * @param user
     */
    private void saveUserRoles(UserDTO user) {
        if (!CollectionUtils.isEmpty(user.getRoles())) {
            List<Long> roleIds = extractRoleIds(user);
            if (userRoleMapper.saveBatch(user.getUserId(), roleIds) < roleIds.size()) {
                throw new BusinessException("用户角色添加失败");
            }
        }
    }

    /**
     * 对象转换
     * @param user
     * @return
     */
    private UserDTO convertToUserDTO(TSysUser user) {
        return Optional.ofNullable(user)
                .map(u -> {
                    UserDTO userDTO = BeanConvertUtils.convertTo(u, UserDTO::new);
                    List<TSysRole> roleList = userRoleMapper.listByUserId(u.getUserId());
                    List<TSysMenu> menuList = roleMenuMapper.listMenuByUserId(u.getUserId(), null);
                    userDTO.setRoles(CollectionUtils.isEmpty(roleList) ? Collections.emptyList() : roleList);
                    userDTO.setAuthorities(CollectionUtils.isEmpty(menuList) ? Collections.emptyList() : menuList);
                    return userDTO;
                })
                .orElse(null);
    }

    /**
     * 取出所以角色id
     * @param user
     * @return
     */
    private List<Long> extractRoleIds(UserDTO user) {
        return user.getRoles().stream().map(TSysRole::getRoleId).collect(Collectors.toList());
    }
}